/* OscarPacketAnalyser.java
 *
 * Copyright 2011 Aleksey Konovalov
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 * 
 */
package org.jimm.protocols.icq.core;

import java.io.DataInputStream;
import java.io.IOException;

import android.util.Log;
import org.jimm.protocols.icq.Snac;
import org.jimm.protocols.icq.core.exceptions.LoginException;
import org.jimm.protocols.icq.exceptions.BadPacketException;
import org.jimm.protocols.icq.packet.received.AuthorizationReply;
import org.jimm.protocols.icq.packet.received.ReceivedPackedRegistry;
import org.jimm.protocols.icq.packet.received.ReceivedPacket;
import org.jimm.protocols.icq.packet.sent.generic.AuthorizationRequest;
import org.jimm.protocols.icq.packet.sent.generic.SignonCommand;

/**
 * <p>
 * Created by
 * 
 * @author Fabrice Michellonet
 * @author Samolisov Pavel
 * @author Konovalov Aleksey
 */
public class OscarPacketAnalyser {

	private static final String LOG_TAG = "ICQ:OscarPacketAnalyser";

	private final OscarConnection connection;
	private int nbPacket = 0;

	public OscarPacketAnalyser(OscarConnection connection) {
		this.connection = connection;
	}

	public final void initialize() {
		nbPacket = 0;
	}

	/**
	 * The function is where we manage the received packets. Recognize them,
	 * analyse and give an answer to the server.
	 * 
	 * @param packet
	 *            The byte array received from the ICQ server.
	 * @throws LoginException
	 * @throws IOException
	 * @throws BadPacketException
	 */
	protected final void handlePacket(DataInputStream packet) throws LoginException,
			IOException, BadPacketException {
		++nbPacket;
		boolean handled = false;
		try {
			handled = handleInitialPackets(packet);
		} catch (LoginException E) {
			throw new LoginException(E.getErrorType(), E);
		}

		// "normal" service
		if (!handled) {
			try {
				handleService(packet);
			} catch (Exception e) {
				Log.e(LOG_TAG,
						"failed to service packet (continuing with other packets)",
						e);
			}
		}
	}

	private final boolean handleInitialPackets(DataInputStream packet)
			throws LoginException, IOException, BadPacketException {
		switch(nbPacket) {
		case 1:
			connection.sendFlap(new AuthorizationRequest(
					connection.getUserId(), connection.getPassword()));
			break;
		case 2:
			AuthorizationReply reply = new AuthorizationReply(packet);
			reply.execute(connection);
			break;
		case 3:
			/* BOS hello */
			connection.sendFlap(new SignonCommand(connection.getCookie()));
			break;
		default:
			return false;
		}
		return true;
	}

	protected final void handleService(DataInputStream packet) throws Exception {
		ReceivedPacket receivedFlap = new ReceivedPacket(packet, true);
		int familyId = receivedFlap.getSnac().getFamilyId();
		int subTypeId = receivedFlap.getSnac().getSubTypeId();

		Log.d(LOG_TAG, "Received " + familyId + " - " + subTypeId);

		// TODO
		// Dumper.log(packet, true, 8, 16);

		try {
			packet.reset();
			ReceivedPacket packetHandler = ReceivedPackedRegistry
					.getPacketHandler(familyId, subTypeId, packet);
			if (packetHandler == null) {
				Log.w(LOG_TAG, "Unknown packet (familyId = " + familyId
						+ ", subType = " + subTypeId);
				return;
			}

			packetHandler.execute(connection);
			packetHandler.notifyEvent(connection);
			packetHandler.matchRequest(connection);

			// if logged to the Server
			if (familyId == Snac.BOS_FAMILY && subTypeId == Snac.SRV_REPLYBOS_COMMAND) {
				connection.setAuthorized(true);
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			Log.e(LOG_TAG, "Could not parse packet", ex);
		}
	}

	/**
	 * This method gives access to the OscarConnection class.
	 * 
	 * @return The filtering engine.
	 */
	public final OscarConnection getConnection() {
		return connection;
	}
}
